﻿using System;
using System.Linq;
using System.Runtime.Serialization;
using BrainTechLLC.Communication;
using BrainTechLLC;
using System.Net;
using BrainTechLLC.ThreadSafeObjects;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.Collections.Generic;
using System.Text;
using UserInterface;
using System.Collections.ObjectModel;
using System.IO;
using Mud.EmlenMudMain;

namespace BrainTechLLC.Silverlight.ClientApplication.Web
{
    public partial class DataService
    {
        [OperationContract, FaultContract(typeof(Fault))]
        public long StoreGameChar(int uniqueId, GameChar o)
        {
            return StoreWithFaultSupport(uniqueId, o);
        }

        [OperationContract, FaultContract(typeof(Fault))]
        public long StoreAbility(int uniqueId, Ability o)
        {
            return StoreWithFaultSupport(uniqueId, o);
        }

        [OperationContract, FaultContract(typeof(Fault))]
        public long StoreLocationEdge(int uniqueId, LocationEdge o)
        {
            return StoreWithFaultSupport(uniqueId, o);
        }

        [OperationContract, FaultContract(typeof(Fault))]
        public long StoreEdgeData(int uniqueId, EdgeData o)
        {
            return StoreWithFaultSupport(uniqueId, o);
        }

        [OperationContract, FaultContract(typeof(Fault))]
        public long StoreState(int uniqueId, State o)
        {
            return StoreWithFaultSupport(uniqueId, o);
        }

        [OperationContract, FaultContract(typeof(Fault))]
        public long StoreMedia(int uniqueId, Media o)
        {
            return StoreWithFaultSupport(uniqueId, o);
        }

        [OperationContract, FaultContract(typeof(Fault))]
        public long StoreStateTemplate(int uniqueId, StateTemplate o)
        {
            return StoreWithFaultSupport(uniqueId, o);
        }

        [OperationContract, FaultContract(typeof(Fault))]
        public long StoreItemTemplate(int uniqueId, ItemTemplate o)
        {
            return StoreWithFaultSupport(uniqueId, o);
        }

        [OperationContract, FaultContract(typeof(Fault))]
        public long StoreItem(int uniqueId, Item o)
        {
            return StoreWithFaultSupport(uniqueId, o);
        }

        [OperationContract, FaultContract(typeof(Fault))]
        public long StoreArea(int uniqueId, Area o)
        {
            return StoreWithFaultSupport(uniqueId, o);
        }

        [OperationContract, FaultContract(typeof(Fault))]
        public long StoreReset(int uniqueId, Reset o)
        {
            return StoreWithFaultSupport(uniqueId, o);
        }

        [OperationContract, FaultContract(typeof(Fault))]
        public long StoreGameCharTemplate(int uniqueId, GameCharTemplate o)
        {
            return StoreWithFaultSupport(uniqueId, o);
        }

        [OperationContract, FaultContract(typeof(Fault))]
        public long StoreTemplate(int uniqueId, Template o)
        {
            return StoreWithFaultSupport(uniqueId, o);
        }

        [OperationContract, FaultContract(typeof(Fault))]
        public long StoreGameThing(int uniqueId, GameThingBaseClass o)
        {
            return StoreWithFaultSupport(uniqueId, o);
        }

        [OperationContract, FaultContract(typeof(Fault))]
        public long StoreGameLocation(int uniqueId, GameLocation o)
        {
            return StoreWithFaultSupport(uniqueId, o);
        }

        [OperationContract, FaultContract(typeof(Fault))]
        public long StoreChannel(int uniqueId, Channel o)
        {
            return StoreWithFaultSupport(uniqueId, o);
        }

        public static long StoreWithFaultSupport<T>(int uniqueId, T param2) where T : class, IGameThing, IAssociatedID
        {
            return WithFaultSupport<long, int, T>(uniqueId, param2, (p1, p2) => Store<T>(p1, p2));
        }

        public static TRet WithFaultSupport<TRet, TParam1, TParam2>(TParam1 param1, TParam2 param2, Func<TParam1, TParam2, TRet> execute)
        {
            try
            {
                return execute(param1, param2);
            }
            catch (Exception e)
            {
                GlobalLogger.Log(e, LogSeverity.Critical, true);
                throw new FaultException<Fault>(new Fault(e.ToString()));
            }
        }

        public static TRet WithFaultSupport<TRet, TParam1>(TParam1 param1, Func<TParam1, TRet> execute)
        {
            try
            {
                return execute(param1);
            }
            catch (Exception e)
            {
                GlobalLogger.Log(e, LogSeverity.Critical, true);
                throw new FaultException<Fault>(new Fault(e.ToString()));
            }
        }

        public static TRet WithFaultSupport<TRet>(Func<TRet> execute)
        {
            try
            {
                return execute();
            }
            catch (Exception e)
            {
                GlobalLogger.Log(e, LogSeverity.Critical, true);
                throw new FaultException<Fault>(new Fault(e.ToString()));
            }
        }

        public static void WithFaultSupport(Action execute)
        {
            try
            {
                execute();
            }
            catch (Exception e)
            {
                GlobalLogger.Log(e, LogSeverity.Critical, true);
                throw new FaultException<Fault>(new Fault(e.ToString()));
            }
        }

        public static long Store<T>(int uniqueId, T toStore) where T : class, IGameThing, IAssociatedID
        {
            T item = Everything.Find<T>(toStore.AssociatedID);

            if (item == null || toStore.AssociatedID <= 0)
            {
                item = toStore;
                item.Register();
                return item.AssociatedID;
            }
            else
            {
                TypeAndProperties props = typeof(T).GetTypeAndProperties();

                props.ForEachProperty((prop) =>
                {
                    if (!prop.PropertyDescriptor.IsReadOnly)
                    {
                        List<Attribute> attrs = prop.Attributes(typeof(DoNotWriteBackAttribute));
                        var found = (attrs == null) ? null : attrs.Find((a) => (a is DoNotWriteBackAttribute) && (a as DoNotWriteBackAttribute).NoWriteback);

                        if (found == null)
                        {
                            object val = prop.GetValue(toStore);
                            prop.SetValue(item, val);
                        }
                    }
                });

                return toStore.AssociatedID;
            }
        }

    }
}
